package server;

import pojo.NetData;

import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

public class AOPServer implements Runnable {
    private final ServerSocket server;
    private volatile boolean flage = false;

    /*
     * key 接口名称
     * value 接口对应的实现类
     * */
    private final Map<String, Object> map = new HashMap<>();

    public AOPServer(int port) throws IOException {
        this.server = new ServerSocket(port);
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            flage = false;
            System.out.println("服务端关闭了");
        }));
    }

    /**
     * 添加一个暴露方法
     *
     * @param api  需要代理的类
     * @param impl 对应的实现
     */
    public void expose(Class<?> api, Object impl) {
        map.put(api.getName(), impl);
    }

    /**
     * 停止
     */
    public void stop() {
        flage = false;
    }

    /**
     * 根据远程发送的信息找到本地的实现，然后执行方法，将返回值返回
     *
     * @param oin 从套接字(Socket)得到的输入流
     * @return 增强的方法的返回值
     */
    public NetData enhance(ObjectInputStream oin) throws IOException, ClassNotFoundException {
        /*直接读取发送过来的NetData*/
        NetData netData = (NetData) oin.readObject();
        System.out.println(server.getLocalPort() + ":发送过来的数据 = " + netData);
        /*
         * ------------由于是实现的接口，所以方法不会是私有的，即使不是接口，私有方法也不能让其他人随意调用
         * 从map根据接口类名得到实现类
         * */
        Object o = map.get(netData.getClassName());
        if (o == null) {
            netData.setMsgAndCode("未暴露此接口", 4L);
            return netData;
        }
        Class<?> aClass = o.getClass();
        /*反射得到方法*/
        Method method = null;
        try {
            method = aClass.getMethod(netData.getFunctionName(), netData.getParameterTypes());
            /*反射执行方法并返回方法的返回值*/
            netData.setResultAndCode(method.invoke(o, netData.getParameters()));
        } catch (NoSuchMethodException e) {
            netData.setMsgAndCode("反射取得方法失败", 1L);
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            netData.setMsgAndCode("反射执行方法失败", 2L);
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            netData.setMsgAndCode("反射执行方法失败", 3L);
            e.printStackTrace();
        }
        return netData;
    }

    @Override
    public void run() {
        System.out.println("服务启动了:" + server.getLocalPort());
        flage = true;
        while (flage) {
            try {
                Socket socket = server.accept();

                ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
                ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
                if (new Random().nextInt(10) > 5) {
                    System.out.println("模拟出错" + server.getLocalPort());
                    objectInputStream.close();
                    objectOutputStream.close();
                } else {
                    //将调用的方法执行并将结果返回
                    objectOutputStream.writeObject(enhance(objectInputStream));
                    /*关流
                     * 当Socket的流关闭时，Socket会自动关闭
                     * */
                    objectOutputStream.close();
                    objectInputStream.close();
                    //stop();
                }
            } catch (IOException | ClassNotFoundException e) {
                System.out.println("流操作失败");
                e.printStackTrace();
            }
        }
    }
}
